Testing Polyglot Persistence Done Right

Testing with mocks only proves you know how to write mocks.


Dan Allen

Next
Introduction

Next
Challenges of Persistence Tests

FIRST Rules

Fast
Run more often
Isolated
Can be executed in any order
Repeatable
Always return the same result
Self-Validating
Know exactly their purpose
Timely
Run before code

Most violated rules in persistence tests

Fast

Isolated

Isolated

PhoneTest.java
@Inject
PhoneService phoneService;

@Test
public void should_insert_phone() {
	phoneService.save(new Phone());
}

@Test
public void should_count_phones() {
	int numberOfPhones = phoneService.count(); (1)
	assertThat(numberOfPhones, equalTo(??));
}
1Depending on execution order the count query returns different number

Next
Solutions

fast
Embedded In-Memory Databases

Fast

HSQLDB
http://hsqldb.org/
MongoDB
https://github.com/fakemongo/fongo
Neo4j
http://www.neo4j.org/
Infinispan
http://infinispan.org/
Cassandra
http://cassandra.apache.org/
isolated
Clean-Insert strategy

Isolation

DBUnit
http://dbunit.sourceforge.net/
Arquillian PE
https://github.com/arquillian/arquillian-extension-persistence
NoSQLUnit
https://github.com/lordofthejars/nosql-unit

Recap

Testing SQL databases?

Testing NoSQL databases?

nosqlunit
plugin2
Not single point of access

Supported Engines

startStop
Starting/Stopping Databases

Manging MongoDB Lifecycle

import static com.lordofthejars.nosqlunit.mongodb.ManagedMongoDb.MongoServerRuleBuilder.newManagedMongoDbRule;

@ClassRule
public static ManagedMongoDb managedMongoDb = newManagedMongoDbRule().mongodPath("/opt/mongo").build(); (1)
1Starts a MongoDB instance installed on /opt/mongo
seed
Seeding Database with Known Data

Seeding to remote Redis

@Rule
public MongoDbRule remoteMongoDbRule = new MongoDbRule(mongoDb().databaseName("test").host("host").build());; (1)

@Test
    @UsingDataSet(locations="initialData.json", loadStrategy=LoadStrategyEnum.CLEAN_INSERT) (2)
    @ShouldMatchDataSet(location="expectedData.json") (3)
    public void book_should_be_inserted_into_repository() {
1Establish a connection to given host
2Clean the Redis instance and populate with given dataset.
3After test expectations are run

initialData.json

{
    "Book":
    [
        {"title":"The Hobbit","numberOfPages":293},
        {"title":"The Lord Of The Rings","numberOfPages":1299}
    ]
}

Recap

but my tests run within a container

Bring Tests to runtime

Next
Origin of the Problem

EntityManager injection

SeriesWithPersistenceContext.java
@Stateless
public class SeriesWithPersistenceContext {

	@PersistenceContext
	private EntityManager entityManager;

	public void createSerie(Serie serie) {
		this.entityManager.persist(serie);
	}
}

EJB for NoSQL

PersonSessionBean.java
@Resource
String host;

@Resource
int port;

@PostConstruct
private void initDB() {
    try {
        Mongo m = new Mongo(host, port);
        DB db = m.getDB("personDB");
        //...
    } catch (UnknownHostException ex) {
        getLogger(PersonSessionBean.class.getName()).log(Level.SEVERE, null, ex);
    }
}
arquillian

Conclusions

github
github.com/lordofthejars/bjugbank

Bartosz Majsak · Alex Soto